package org.easy.tool.common;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.CharsetUtil;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author Valley
 * Created by Valley on 2023/7/14 16:08
 */
public class FileIOUtil {

    /**
     * 功能：将文件流转为base64
     */
    public static Object file2Base64(String filePath) throws Exception {
        File file = new File(filePath);
        InputStream in = Files.newInputStream(file.toPath());
        byte[] bytes = new byte[(int) file.length()];
        int read = in.read(bytes);
        String base64 = Base64.getEncoder().encodeToString(bytes);
        in.close();
        return base64;
    }

    /**
     * 功能：将base64字符串转换为文件
     */
    public static void base64ToFile(String base64, String outFilePath) throws Exception {
        byte[] bytes = Base64.getDecoder().decode(base64);
        FileOutputStream fos = new FileOutputStream(outFilePath);
        BufferedOutputStream bos = new BufferedOutputStream(fos);
        bos.write(bytes);
        fos.close();
    }

    /**
     * 功能：将某个路径生成File对象
     */
    public static File file(String filePath) {
        File file = cn.hutool.core.io.FileUtil.file(filePath);
        return mkDirs(file);
    }

    /**
     * 功能：下载网络链接文件到本地地址
     */
    public static long download(String uri, String dest) {
        return HttpUtil.download(uri, dest);
    }

    /**
     * 功能：获取文件输入流，参数是File
     */
    public static InputStream read(File file) {
        return cn.hutool.core.io.FileUtil.getInputStream(file);
    }

    /**
     * 功能：获取文件输入流，参数是文件地址
     */
    public static InputStream read(String path) {
        return cn.hutool.core.io.FileUtil.getInputStream(path);
    }

    /**
     * 功能：获取文件输出流，参数是File
     */
    public static OutputStream write(File file) {
        return cn.hutool.core.io.FileUtil.getOutputStream(file);
    }

    /**
     * 功能：获取文件输出流，参数是文件地址
     */
    public static OutputStream write(String path) {
        return cn.hutool.core.io.FileUtil.getOutputStream(path);
    }


    /**
     * 功能：将某个网络路径生成File对象
     */
    public static File file(URI uri) {
        File file = cn.hutool.core.io.FileUtil.file(uri);
        return mkDirs(file);
    }

    /**
     * 功能：将每个File对象自动生成父文件夹
     */
    public static File mkDirs(File file) {
        if (!file.getParentFile().exists()) {
            file.mkdirs();
        }
        return file;
    }

    /**
     * 功能：将每个File对象自动生成父文件夹
     */
    public static void mkDirs(String filePath) {
        File file = new File(filePath);
        if (!file.getParentFile().exists()) {
            file.mkdirs();
        }
    }

    /**
     * 功能：将数据按行写入本地文件
     */
    public static boolean writeLines(List<String> dataList, String path) {
        return cn.hutool.core.io.FileUtil.writeLines(dataList, path, CharsetUtil.CHARSET_UTF_8).exists();
    }

    /**
     * 功能：实现文件追加
     */
    public static void append(String path, String content) {
        cn.hutool.core.io.FileUtil.appendUtf8String(content, path);
    }

    /**
     * 功能：实现文件追加
     */
    public static void append(String path, List<String> contentList) {
        contentList.forEach(s -> append(path, s));
    }


    /**
     * 功能：将本地文件中的每一行读取出来
     */
    public static List<String> readLines(String path) {
        return cn.hutool.core.io.FileUtil.readLines(path, CharsetUtil.CHARSET_UTF_8);
    }


    /**
     * 功能：将某个路径(xxx/xxx.txt)复制到某个路径(xxx/xxx.txt)
     */
    public static File copyFile(String source, String dest) {
        File copy = cn.hutool.core.io.FileUtil.copy(source, dest, true);
        return mkDirs(copy);
    }

    /**
     * 功能：复制某个文件(xxx/xxx.txt)到某个路径(xxx/xxx.txt)
     */
    public static File copyFile(File sourceFile, String dest) {
        File destFile = new File(dest);
        File copy = cn.hutool.core.io.FileUtil.copy(sourceFile, destFile, true);
        return mkDirs(copy);
    }


    /**
     * 功能：将文件流写入指定路径(xxx/xxx.txt)
     */
    public static File writeFile(InputStream in, String dest) {
        return cn.hutool.core.io.FileUtil.writeFromStream(in, dest);
    }

    /**
     * 功能：删除文件，支持文件和文件夹
     */
    public static boolean delete(File file) {
        return cn.hutool.core.io.FileUtil.del(file);
    }

    /**
     * 功能：删除文件，支持文件和文件夹
     */
    public static boolean delete(String path) {
        return cn.hutool.core.io.FileUtil.del(path);
    }

    /**
     * 功能：通过文件夹，文件名获取文件
     */
    public static File file(String dir, String fineName) {
        return cn.hutool.core.io.FileUtil.file(dir, fineName);
    }

    /**
     * 功能：获取某个文件夹下所有的文件List
     */
    public static List<String> dir(String dir) {
        return cn.hutool.core.io.FileUtil.listFileNames(dir);
    }

    /**
     * 功能：获取某个文件夹下所有的文件List，全称
     */
    public static List<String> dirStr(String dir) {
        return dir(dir).stream()
                .map(s -> dir + File.separator + s)
                .collect(Collectors.toList());
    }

    /**
     * 功能：获取某个文件夹下所有的文件List
     */
    public static List<File> dirFile(String dir) {
        return dir(dir).stream()
                .map(s -> FileIOUtil.file(dir, s))
                .collect(Collectors.toList());
    }

    /**
     * 功能：创建临时文件夹
     */
    public static File createTempDir(String path) {
        File file = new File(path);
        if (!file.exists()) file.mkdirs();
        return file;
    }

    /**
     * 功能：将本地文件转化为输出流
     */
    public static InputStream fileToInput(File file) {
        return IoUtil.toStream(file);
    }

    /**
     * 功能：将文件转化为字节
     */
    public static byte[] fileToByte(File file) throws Exception{
        ByteArrayOutputStream out = (ByteArrayOutputStream)fileToOut(file);
        byte[] bytes = out.toByteArray();
        out.close();
        return bytes;
    }

    /**
     * 功能：将文件转化为字节
     */
    public static byte[] fileToByte(String filePath) throws Exception{
        ByteArrayOutputStream out = (ByteArrayOutputStream)fileToOut(new File(filePath));
        byte[] bytes = out.toByteArray();
        out.close();
        return bytes;
    }

    /**
     * 功能：将文件转化为输出流
     */
    public static OutputStream fileToOut(File file) throws Exception{
        InputStream in = fileToInput(file);
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int len;
        byte[] buffer = new byte[1024];
        while ((len = in.read(buffer)) != -1) {
            out.write(buffer, 0, len);
        }
        in.close();
        return out;
    }

    /**
     * 功能：将输入流转化为文件
     */
    public static void inputToFile(InputStream in, String path) throws Exception{
        OutputStream out = Files.newOutputStream(new File(path).toPath());
        IoUtil.copy(in, out);
        out.flush();
        out.close();
    }

    /**
     * 功能：将请求中的文件流转化为本地文件
     */
    public static void uploadFile(HttpServletRequest req, String file) throws Exception{
        //直接用req.getInputStream()不行，需要进行封装
        InputStream in = handleFileUpload(req);
        inputToFile(in, file);
        in.close();
    }

    /**
     * 功能：从Http请求中获取文件输入流
     */
    public static InputStream handleFileUpload(HttpServletRequest req) {
        // 获取上传文件的总大小
        long size = req.getContentLength();
        // 创建一个数组来存储读取的数据
        byte[] buffer = new byte[(int)size];
        // 获取输入流
        BufferedInputStream inputStream = null;
        try {
            inputStream = new BufferedInputStream(req.getInputStream());
            int bytesRead = inputStream.read(buffer);
            // 在这里处理文件内容，bytesRead是读取的字节数，buffer数组是包含文件内容的字节数组
            System.out.println(bytesRead+"bytes");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return inputStream;
    }

    /**
     * 功能：将指定本地文件下载到浏览器
     */
    public static void download(HttpServletRequest req, HttpServletResponse res, String path) throws Exception{
        HttpUtil.downloadFile(req, res, new File(path));
    }

    /**
     * 功能：将字节数组写入到指定路径文件
     */
    public static void byteToFile(byte[] bytes, String outFile) throws Exception{
        BufferedOutputStream bos = new BufferedOutputStream(
                Files.newOutputStream(Paths.get(outFile)));
        IoUtil.write(bos, true, bytes);
    }

}
